from uscarp import *
import matplotlib.pyplot as plt


def scrapyData(start,end):
    records = list()
    for year in range(start, end+1):
        record = dict()
        season = str(year) + '-' + str(year + 1)[-2:]
        url = "https://stats.nba.com/stats/leaguedashplayerstats?College=&Conference=&Country=&" \
              "DateFrom=&DateTo=&Division=&DraftPick=&DraftYear=&GameScope=&GameSegment=&Height=&" \
              "LastNGames=0&LeagueID=00&Location=&MeasureType=Base&Month=0&OpponentTeamID=0&Outcome=&" \
              "PORound=0&PaceAdjust=N&PerMode=PerGame&Period=0&PlayerExperience=&PlayerPosition=&" \
              "PlusMinus=N&Rank=N&Season=%s&SeasonSegment=&SeasonType=Regular+Season&ShotClockRange=&" \
              "StarterBench=&TeamID=0&VsConference=&VsDivision=&Weight=" % season
        data = json.loads(getHtml(url))["resultSets"][0]['rowSet']
        for item in data:
            if item[31] and item[2]:
                record[item[0]] = (item[2], item[31])
        records.append(record)
        print('finish %d' % year)
    with open('records.json', 'w') as json_file:
        json.dump(records, json_file)

def getRecommend(team1,team2,sim,filter):
    delta = list()
    for t in team2:
        p1 = {p for p in team1[t]}
        p2 = {p for p in team2[t]}
        for p in p2 - p1:
            sum1 = 0
            sum2 = 0
            if p not in sim :
                continue
            for pp in p1:
                if sim[p][pp] <= filter:
                    continue
                sum1 += team1[t][pp] * sim[p][pp]
                sum2 += sim[p][pp]
                # print(p,pp,team1[t][pp],sim[p][pp])
            if sum2>0:
                delta.append((p, round(sum1 / sum2), team2[t][p]))
    delta = sorted(delta)
    # print(delta)
    mean = sum([abs(d[1]-d[2]) for d in delta])/len(delta)
    return mean

def genRate(start,end):
    with open('records.json', 'r') as json_file:
        records = json.load(json_file)
    records = records[start-1:end+1]##[0-21)
    n = end-start+2##19+2
    m = int(n*0.8)

    ##calc delta
    for i in range(len(records) - 1, 0, -1):
        for p in records[i]:
            if p not in records[i - 1]:
                records[i][p][1] = 0
            else:
                records[i][p][1] = round(records[i][p][1] - records[i - 1][p][1], 2)

    scores1,max1,min1 = buildScore(records[1:m])
    scores2,max2,min2 = buildScore(records[m:n])
    maxx = max(max1,max2)
    minx = min(min1,min2)
    formatScore(scores1,maxx,minx)
    # print('--------------------')
    formatScore(scores2,maxx,minx)
    return scores1,scores2

def buildScore(records):
    data = dict()
    teams = set()
    players = set()
    for rc in records:
        for p in rc:
            t = rc[p][0]
            s = rc[p][1]
            if s == 0:
                continue  ##未评分球员
            teams.add(t)
            if p not in data:
                data[p] = {t: [s]}
            else:
                if t not in data[p]:
                    data[p][t] = [s]
                else:
                    data[p][t].append(s)
    for p in data:
        if len(data[p]) > 2:
            players.add(p)
    scores = {p: {t: 0 for t in teams} for p in players}
    maxx = 0
    minx = 100
    for p in scores:
        for t in data[p]:
            for i in range(1, len(data[p][t])):
                data[p][t][i] += data[p][t][i - 1]
            scores[p][t] = max(data[p][t])
            maxx = max(maxx, scores[p][t])
            minx = min(minx, scores[p][t])
    return scores,maxx,minx

def formatScore(scores,maxx,minx):
    for p in scores:
        for t in scores[p]:
            if scores[p][t] != 0:
                scores[p][t] = int((scores[p][t] - minx) / (maxx - minx) * 10 + 0.999)
    # for p in scores:
    #     print(p, list(scores[p].values()))

def genSim(scores,index):
    sim = {p: {p: 0 for p in scores} for p in scores}
    log = set()
    if index == 3:
        pm = every_mean(scores)
    for p1 in sim:
        for p2 in sim[p1]:
            if (p1,p2) in log or (p2,p1)  in log:
                continue
            log.add((p1,p2))
            if index ==1:
                sim[p1][p2] = cos(scores[p1], scores[p2])
            if index == 2:
                sim[p1][p2] = pearson(scores[p1], scores[p2])
            if index == 3:
                sim[p1][p2] = acos(scores[p1], scores[p2],pm)
            sim[p2][p1] = sim[p1][p2]
    return sim

def convert(real):
    teams = dict()
    for p in real:
        for t in real[p]:
            if real[p][t] == 0:
                continue
            if t not in teams:
                teams[t] = {p: real[p][t]}
            else:
                teams[t][p] = real[p][t]
    return teams

def cos(v1, v2):  ##O(U)
    res1 = res2 = res3 = 0
    for u in set(v1.keys())&set(v2.keys()):
        res1 += v1[u] * v2[u]
    for u in v1:
        res2 += v1[u] ** 2
    for u in v2:
        res3 += v2[u] ** 2
    if res2 * res3 == 0:
        return 0
    return res1 / ((res2 * res3) ** 0.5)

def acos(v1,v2,pm):
    res1 = res2 = res3 = 0
    for u in set(v1.keys())&set(v2.keys()):
        if v1[u]!=0 and v2[u]!=0:
            res1 += (v1[u]-pm[u]) * (v2[u]-pm[u])
    for u in v1:
        if v1[u] != 0:
            res2 += (v1[u]-pm[u]) ** 2
    for u in v2:
        if v2[u] != 0:
            res3 += (v2[u]-pm[u]) ** 2
    if res2 * res3 == 0:
        return 0
    return res1 / ((res2 * res3) ** 0.5)

def pearson(v1,v2):
    m1 = mean(v1)
    m2 = mean(v2)
    res1 = res2 = res3 = 0
    for u in set(v1.keys())&set(v2.keys()):
        if v1[u]!=0 and v2[u]!=0:
            res1 += (v1[u]-m1) * (v2[u]-m2)
    for u in v1:
        if v1[u] != 0:
            res2 += (v1[u]-m1) ** 2
    for u in v2:
        if v2[u] != 0:
            res3 += (v2[u]-m2) ** 2
    if res2 * res3 == 0:
        return 0
    return res1 / ((res2 * res3) ** 0.5)

def every_mean(scores):
    pm = dict()
    scores = convert(scores)
    for p in scores:
        pm[p] = mean(scores[p])
    return pm

def mean(vv):
    sum = 0
    num = 0
    for v in vv.values():
        if v!=0:
            sum+=v
            num+=1
    if num ==0:
        return 0
    else:
        return sum/num


if __name__ == '__main__':
    scores, real = genRate(1, 20)
    team1 = convert(scores)  ##模型
    team2 = convert(real)  ##预测
    a = list()
    b = [0.03, 0.04, 0.06,0.08 ,0.1, 0.15, 0.2,0.25, 0.3,0.35, 0.4,0.5,0.6]
    for i in [1,2,3]:
        tmp = list()
        sim = genSim(scores, i)
        for f in b:
            tmp.append(round(getRecommend(team1,team2,sim,f),2))
        a.append(tmp)
    plt.plot(b, a[0], 'go-.', b, a[1], 'rx-.', b, a[2], '*-.')
    plt.ylabel('mean')
    plt.xlabel('sim')
    plt.show()
